package cn.minhx.dtm.starter.core.util;

import java.lang.reflect.Method;
import java.util.*;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.util.ClassUtils;

/**
 * 反射工具类
 *
 * @author min
 */
public final class ReflectionUtils {

	private static final Map<String, Class<?>> PRIMITIVE_TYPE_MAP = new HashMap<>();

	static {
		PRIMITIVE_TYPE_MAP.put("byte", byte.class);
		PRIMITIVE_TYPE_MAP.put("short", short.class);
		PRIMITIVE_TYPE_MAP.put("int", int.class);
		PRIMITIVE_TYPE_MAP.put("long", long.class);
		PRIMITIVE_TYPE_MAP.put("float", float.class);
		PRIMITIVE_TYPE_MAP.put("double", double.class);
		PRIMITIVE_TYPE_MAP.put("boolean", boolean.class);
		PRIMITIVE_TYPE_MAP.put("char", char.class);
		PRIMITIVE_TYPE_MAP.put("void", void.class);
	}

	private ReflectionUtils() {
		// 私有构造函数，防止实例化
	}

	/**
	 * 将字符串类型名称列表转换为 Class<?> 类型列表
	 *
	 * @param classNames
	 *            类名列表
	 * @return 对应的Class对象列表
	 */
	public static List<Class<?>> resolveParameterTypes(List<String> classNames) {
		List<Class<?>> parameterTypes = new ArrayList<>(classNames.size());
		for (String typeName : classNames) {
			Class<?> clazz;
			if (PRIMITIVE_TYPE_MAP.containsKey(typeName)) {
				clazz = PRIMITIVE_TYPE_MAP.get(typeName);
			} else {
				try {
					clazz = ClassUtils.forName(typeName, Thread.currentThread().getContextClassLoader());
				} catch (ClassNotFoundException e) {
					throw new IllegalArgumentException("无法找到类: " + typeName, e);
				}
			}
			parameterTypes.add(clazz);
		}
		return parameterTypes;
	}

	/**
	 * 获取指定类中的指定方法
	 *
	 * @param targetClass
	 *            目标类
	 * @param methodName
	 *            方法名
	 * @param parameterTypes
	 *            参数类型
	 * @return 匹配的方法
	 */
	public static Method findMethod(Class<?> targetClass, String methodName, Class<?>... parameterTypes) {
		try {
			// 先尝试直接获取方法（适用于方法签名完全匹配的情况）
			return targetClass.getMethod(methodName, parameterTypes);
		} catch (NoSuchMethodException e) {
			// 如果找不到方法，则遍历所有方法，进行参数兼容性匹配
			for (Method method : targetClass.getMethods()) {
				if (method.getName().equals(methodName)
						&& isParameterTypesCompatible(method.getParameterTypes(), parameterTypes)) {
					return method;
				}
			}
			throw new IllegalArgumentException(String.format("在类 %s 中找不到匹配的方法: %s，参数类型: %s", targetClass.getName(),
					methodName, Arrays.toString(parameterTypes)));
		}
	}

	/**
	 * 判断给定的参数类型是否与方法参数类型兼容
	 *
	 * @param methodParameterTypes
	 *            方法的参数类型
	 * @param givenParameterTypes
	 *            给定的参数类型
	 * @return 是否兼容
	 */
	private static boolean isParameterTypesCompatible(Class<?>[] methodParameterTypes, Class<?>[] givenParameterTypes) {
		if (methodParameterTypes.length != givenParameterTypes.length) {
			return false;
		}
		for (int i = 0; i < methodParameterTypes.length; i++) {
			if (!isAssignableFrom(methodParameterTypes[i], givenParameterTypes[i])) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 判断两个类型是否兼容（考虑基本类型与包装类型的自动转换）
	 *
	 * @param targetType
	 *            目标类型
	 * @param sourceType
	 *            源类型
	 * @return 是否兼容
	 */
	private static boolean isAssignableFrom(Class<?> targetType, Class<?> sourceType) {
		// 处理基本类型与包装类型的兼容性
		if (targetType.isPrimitive()) {
			targetType = ClassUtils.resolvePrimitiveIfNecessary(targetType);
		}
		if (sourceType.isPrimitive()) {
			sourceType = ClassUtils.resolvePrimitiveIfNecessary(sourceType);
		}
		return targetType.isAssignableFrom(sourceType);
	}

	/**
	 * 获取原始对象
	 *
	 * @param bean
	 *            代理对象或者原始对象
	 * @return 原始对象
	 */
	public static Object getSourceObject(Object bean) {
		if (!(bean instanceof Advised)) {
			return bean;
		}
		TargetSource targetSource = ((Advised) bean).getTargetSource();
		try {
			return targetSource.getTarget();
		} catch (Exception e) {
			throw new RuntimeException("获取原始对象失败", e);
		}
	}
}
